# coding=utf-8
import math
import re
import sys
import threading
import traceback
from datetime import datetime
from typing import Dict, Any, List

import akshare as ak
import numpy as np
import pandas as pd
import pyqtgraph as pg
import talib
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from dateutil.relativedelta import relativedelta

# 1-->boll ,2-->ma
stock_index = 1

pg.setConfigOption('background', 'k')
pg.setConfigOption('foreground', 'w')

from PyQt5.QtCore import *
from PyQt5.QtGui import *

color_table = {'line_desc': 'green'}


# 返回今天的日期
def res_date_normal_str():
    return datetime.now().strftime('%Y-%m-%d')


# 返回今年第一天
def res_current_year_first_day():
    now_day = datetime.today()
    current_year = now_day.year
    res_str = f"{current_year}-01-01"
    return res_str
    pass


# 往回推N年的第一天
def res_pre_N_year_first_day(n):
    pre_year_day = (datetime.now() - relativedelta(years=n)).strftime('%Y-%m-%d')
    return pre_year_day


class RotateAxisItem(pg.AxisItem):
    def drawPicture(self, p, axisSpec, tickSpecs, textSpecs):
        p.setRenderHint(p.Antialiasing, False)
        p.setRenderHint(p.TextAntialiasing, True)

        ## draw long line along axis
        pen, p1, p2 = axisSpec
        p.setPen(pen)
        p.drawLine(p1, p2)
        p.translate(0.5, 0)  ## resolves some damn pixel ambiguity

        ## draw ticks
        for pen, p1, p2 in tickSpecs:
            p.setPen(pen)
            p.drawLine(p1, p2)

        p.setPen(self.pen())
        for rect, flags, text in textSpecs:
            # this is the important part
            p.save()
            p.translate(rect.x(), rect.y())
            p.rotate(-30)
            p.drawText(-int(rect.width()), int(rect.height()), int(rect.width()), int(rect.height()), flags, text)
            # restoring the painter is *required*!!!
            p.restore()


class CandlestickItem(pg.GraphicsObject):
    def __init__(self, data):
        pg.GraphicsObject.__init__(self)
        self.data = data  ## data must have fields: time, open, close, min, max
        self.generatePicture()

    def generatePicture(self):
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        p.setPen(pg.mkPen('w'))
        w = (self.data[1][0] - self.data[0][0]) / 3.
        for (t, _open, close, _min, _max) in self.data:
            if _open > close:
                p.setPen(pg.mkPen('#1d953f'))
                p.setBrush(pg.mkBrush('#1d953f'))
            else:
                p.setPen(pg.mkPen('#ef4136'))
                p.setBrush(pg.mkBrush('#ef4136'))
            p.drawLine(QtCore.QPointF(t, _min), QtCore.QPointF(t, _max))
            p.drawRect(QtCore.QRectF(t - w, _open, w * 2, close - _open))
        p.end()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        return QtCore.QRectF(self.picture.boundingRect())


class SegmenttickItem(pg.GraphicsObject):
    def __init__(self, data):
        pg.GraphicsObject.__init__(self)
        self.data = data
        self.generatePicture()

    def generatePicture(self):
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        for (t, val) in self.data:
            if val > 0.0:
                p.setPen(pg.mkPen('r'))
                p.drawLine(QtCore.QPointF(t, 0), QtCore.QPointF(t, val))
            else:
                p.setPen(pg.mkPen('g'))
                p.drawLine(QtCore.QPointF(t, 0), QtCore.QPointF(t, val))
        p.end()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        return QtCore.QRectF(self.picture.boundingRect())


class VolItem(pg.GraphicsObject):
    def __init__(self, data):
        pg.GraphicsObject.__init__(self)
        self.data = data
        self.generatePicture()

    def generatePicture(self):
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        w = 0.25
        for (t, open, close, vol) in self.data:
            if open > close:
                p.setPen(pg.mkPen(color_table['line_desc']))
                p.setBrush(pg.mkBrush(color_table['line_desc']))
                p.drawRect(QtCore.QRectF(t - w, 0, w * 2, vol))
            else:
                p.setPen(pg.mkPen('r'))
                p.drawLines(QtCore.QLineF(QtCore.QPointF(t - w, 0), QtCore.QPointF(t - w, vol)),
                            QtCore.QLineF(QtCore.QPointF(t - w, vol), QtCore.QPointF(t + w, vol)),
                            QtCore.QLineF(QtCore.QPointF(t + w, vol), QtCore.QPointF(t + w, 0)),
                            QtCore.QLineF(QtCore.QPointF(t + w, 0), QtCore.QPointF(t - w, 0)))
        p.end()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        return QtCore.QRectF(self.picture.boundingRect())


class PyQtGraphLineWidget(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.init_data()
        self.init_ui()

        df = self.getDataFromNet(self.code)

        whole_pd_header = ['Date', 'Close', 'Open', 'High', 'Low', 'Increase']
        whole_pd_header2 = ['Date', 'DIFF', 'DEA', 'MACD']
        whole_pd_header3 = ['Date', 'kdj_k', 'kdj_d', 'kdj_j']

        line_data = {
            'title_str': '贵州茅台',
            'whole_header': ['日期', '收盘价', '开盘价', '最高价', '最低价', '涨跌幅'],
            'whole_header2': ['日期', 'DIFF', 'DEA', 'MACD'],
            'whole_pd_header': whole_pd_header,
            'whole_pd_header2': whole_pd_header2,
            'whole_pd_header3': whole_pd_header3,
            'whole_df': df
        }
        self.set_data(line_data)
        pass

    def init_data(self):
        self.please_select_str = '---请选择---'
        self.func_map = {
            '一定上涨': 'a',
            '可能下跌': 'b',
            '可能上涨': 'c'
        }
        self.func_item_list = []
        self.duration_map = {
            '今年': 'a',
            '最近一年': 'b',
            '最近两年': 'c',
            '最近三年': 'd',
            '最近五年': 'e',
            '最近十年': 'f'
        }
        self.pattern_map = {
            '十字星', '两只乌鸦', '三只乌鸦', '三内部上涨和下跌', '三线打击',
            '三外部上涨和下跌', '南方三星', '三个白兵', '弃婴', '大敌当前',
            '捉腰带线', '脱离', '收盘缺影线', '藏婴吞没', '反击线'
            , '乌云压顶', '蜻蜓十字/T形十字', '吞噬模式', '十字暮星', '暮星',
            '向上/下跳空并列阳线', '墓碑十字/倒T十字', '锤头', '上吊线', '母子线',
            '十字孕线', '风高浪大线', '陷阱', '修正陷阱', '家鸽',
            '三胞胎乌鸦', '颈内线', '倒锤头', '反冲形态', '由较长缺影线决定的反冲形态',
            '停顿形态', '条形三明治', '探水竿', '跳空并列阴阳线', '插入',
            '三星', '奇特三河床', '向上跳空的两只乌鸦', '上升/下降跳空三法'
        }
        self.k_content = ['预示着当前趋势反转', '预示股价下跌', '预示股价下跌', '预示着股价上涨', '预示股价下跌',
                          '预示着股价上涨', '预示下跌趋势反转，股价上升', '预示股价上升',
                          '预示趋势反转，发生在顶部下跌，底部上涨', '预示股价下跌'
            , '收盘价接近最高价，预示价格上涨', '预示价格上涨', '预示着趋势持续', '预示着底部反转', '预示趋势反转'
            , '预示着股价下跌', '预示趋势反转', '预示趋势反转', '预示顶部反转', '预示顶部反转',
                          '趋势持续', '预示底部反转', '处于下跌趋势底部,预示反转', '处于上升趋势的顶部，预示着趋势反转',
                          '预示趋势反转，股价上升',
                          '预示着趋势反转', '预示着趋势反转', '趋势继续', '趋势继续', '预示着趋势反转',
                          '预示价格下跌', '预示着下跌继续', '在下跌趋势底部，预示着趋势反转', '存在跳空缺口',
                          '与反冲形态类似，较长缺影线决定价格的涨跌',
                          '预示着上涨结束', '预示着股价上涨', '预示趋势反转', '上升趋势持续', '预示着趋势持续',
                          '预示着趋势反转', '收盘价不高于第二日收盘价，预示着反转，第二日下影线越长可能性越大',
                          '预示股价下跌', '收盘价高于第一日收盘价，预示股价上升']
        self.K_method = ['CDLDOJISTAR', 'CDL2CROWS', 'CDL3BLACKCROWS', 'CDL3INSIDE', 'CDL3LINESTRIKE',
                         'CDL3OUTSIDE', 'CDL3STARSINSOUTH', 'CDL3WHITESOLDIERS', 'CDLABANDONEDBABY', 'CDLADVANCEBLOCK',
                         'CDLBELTHOLD', 'CDLBREAKAWAY', 'CDLCLOSINGMARUBOZU', 'CDLCONCEALBABYSWALL', 'CDLCOUNTERATTACK',
                         'CDLDARKCLOUDCOVER', 'CDLDRAGONFLYDOJI', 'CDLENGULFING', 'CDLEVENINGDOJISTAR',
                         'CDLEVENINGSTAR',
                         'CDLGAPSIDESIDEWHITE', 'CDLGRAVESTONEDOJI', 'CDLHAMMER', 'CDLHANGINGMAN', 'CDLHARAMI',
                         'CDLHARAMICROSS', 'CDLHIGHWAVE', 'CDLHIKKAKE', 'CDLHIKKAKEMOD', 'CDLHOMINGPIGEON',
                         'CDLIDENTICAL3CROWS', 'CDLINNECK', 'CDLINVERTEDHAMMER', 'CDLKICKING', 'CDLKICKINGBYLENGTH',
                         'CDLSTALLEDPATTERN', 'CDLSTICKSANDWICH', 'CDLTAKURI', 'CDLTASUKIGAP', 'CDLTHRUSTING',
                         'CDLTRISTAR', 'CDLUNIQUE3RIVER', 'CDLUPSIDEGAP2CROWS', 'CDLXSIDEGAP3METHODS']
        self.code_map = {
            '贵州茅台': '600519',
            '五粮液': '000858',
            '钧达股份': '002865',
            '康龙化成': '300759',
            '德业股份': '605117',
            '通策医疗': '600763',
            '德方纳米': '300769',
            '宁德时代': '300750',
            '爱美客': '300896',
            '斯达半导': '603290',
            '迈瑞医疗': '300760',
            '比亚迪': '002594',
            '北方华创': '002371',
        }
        self.main_figure_index_map = {
            '布林线': 'a',
            '均线': 'b'
        }
        # 当前股票代码
        self.code = '600519'
        # 当前股票名称
        self.name = ''
        self.color_line = (30, 144, 255)
        self.color_ma_5 = (248, 248, 255)  # 幽灵的白色
        self.color_ma_10 = (255, 255, 0)  # 纯黄
        self.color_ma_20 = (255, 0, 255)  # 紫红色
        self.color_ma_30 = (0, 128, 0)  # 纯绿
        self.color_ma_60 = (30, 144, 255)  # 道奇蓝
        self.color_up = (220, 20, 60)
        self.color_down = (60, 179, 113)
        self.main_fixed_target_list = []  # 主体固定曲线，不能被删除
        self.whole_df = None
        self.whole_header = None
        self.whole_header2 = None
        self.whole_pd_header = None
        self.whole_pd_header2 = None
        self.whole_pd_header3 = None
        self.current_whole_data = None
        self.current_whole_data2 = None
        self.current_whole_df = None
        # 存储标记控件对象
        self.mark_list = []
        self.left_point = 0
        self.choice_stock_list = []
        pass

    def init_ui(self):
        # 控制面板 start
        pattern_tip = QtWidgets.QLabel('模式识别')
        self.pattern_combox = QtWidgets.QComboBox()
        self.pattern_combox.addItem(self.please_select_str)
        self.pattern_combox.addItems(self.pattern_map)
        self.pattern_combox.currentIndexChanged.connect(self.pattern_combox_currentIndexChanged)

        self.content_combox = QtWidgets.QComboBox()
        self.content_combox.addItem(self.please_select_str)
        self.content_combox.addItems(self.k_content)

        self.content_tip = QtWidgets.QLabel('....')

        duration_tip = QtWidgets.QLabel('常用时间')
        self.duration_combox = QtWidgets.QComboBox()
        self.duration_combox.addItem(self.please_select_str)
        self.duration_combox.addItems(list(self.duration_map.keys()))
        self.duration_combox.currentIndexChanged.connect(self.duration_combox_currentIndexChanged)

        combox_tip = QtWidgets.QLabel('功能')
        self.func_combox = QtWidgets.QComboBox()
        self.func_combox.addItem(self.please_select_str)
        self.func_combox.addItems(list(self.func_map.keys()))
        self.func_combox.currentIndexChanged.connect(self.func_combox_currentIndexChanged)
        clear_func_btn = QtWidgets.QPushButton('清空功能区')
        clear_func_btn.clicked.connect(self.clear_func_btn_clicked)

        combox_code = QtWidgets.QLabel('代码')
        self.code_combox = QtWidgets.QComboBox()
        self.code_combox.addItem(self.please_select_str)

        combox_main_figure_index = QtWidgets.QLabel('选择主图指标')
        self.combox_main_figure_index = QtWidgets.QComboBox()
        self.combox_main_figure_index.addItem(self.please_select_str)
        self.combox_main_figure_index.addItems(list(self.main_figure_index_map.keys()))
        self.combox_main_figure_index.currentIndexChanged.connect(self.combox_main_figure_index_currentIndexChanged)

        # 获取股票列表
        stock_info_sz_df = ak.stock_info_a_code_name()
        codelist = stock_info_sz_df["code"]
        name = stock_info_sz_df["name"]
        self.choice_stock_list = [codelist, name]
        self.code_combox.addItems(list(codelist))
        # self.code_combox.addItems(list(self.code_map.keys()))
        self.code_combox.currentIndexChanged.connect(self.code_combox_currentIndexChanged)

        layout_date = QtWidgets.QHBoxLayout()
        layout_date.addWidget(pattern_tip)
        layout_date.addWidget(self.pattern_combox)
        layout_date.addWidget(self.content_combox)
        layout_date.addWidget(self.content_tip)
        layout_date.addSpacing(30)
        layout_date.addWidget(duration_tip)
        layout_date.addWidget(self.duration_combox)
        layout_date.addSpacing(30)
        layout_date.addWidget(combox_tip)
        layout_date.addWidget(self.func_combox)
        layout_date.addWidget(combox_code)
        layout_date.addWidget(self.code_combox)
        layout_date.addWidget(combox_main_figure_index)
        layout_date.addWidget(self.combox_main_figure_index)
        layout_date.addWidget(clear_func_btn)
        layout_date.addStretch(1)
        # 控制面板 end

        self.title_label = QtWidgets.QLabel('均线训练')
        self.title_label.setAlignment(Qt.AlignCenter)
        self.title_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold}')

        xax = RotateAxisItem(orientation='bottom')
        xax.setHeight(h=50)
        xax2 = RotateAxisItem(orientation='bottom')
        xax2.setHeight(h=50)
        self.pw = pg.PlotWidget()
        layout_pw = QtWidgets.QVBoxLayout()
        layout_pw.addWidget(self.pw, 1000)

        self.pw2 = pg.PlotWidget()
        self.vol_label = QtWidgets.QLabel('成交量')
        self.vol_label.setAlignment(Qt.AlignLeft)
        self.vol_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold}')
        layout_pw.addWidget(self.vol_label)
        layout_pw.addWidget(self.pw2, 1)

        self.pw3 = pg.PlotWidget()
        self.macd_label = QtWidgets.QLabel('MACD')
        self.macd_label.setAlignment(Qt.AlignLeft)
        self.macd_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold}')
        layout_pw.addWidget(self.macd_label)
        layout_pw.addWidget(self.pw3, 10)

        self.pw4 = pg.PlotWidget()
        self.kdj_label = QtWidgets.QLabel('KDJ')
        self.kdj_label.setAlignment(Qt.AlignLeft)
        self.kdj_label.setStyleSheet('QLabel{font-size:18px;font-weight:bold}')
        layout_pw.addWidget(self.kdj_label)
        layout_pw.addWidget(self.pw4, 10)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.title_label)
        layout.addLayout(layout_date)
        layout.addLayout(layout_pw)
        self.setLayout(layout)
        self.setWindowTitle("Heaven_Hand K线图分析软件")
        pass

    def set_data(self, data: Dict[str, Any]):
        title_str = data['title_str']
        whole_header = data['whole_header']
        whole_header2 = data['whole_header2']
        whole_df = data['whole_df']
        whole_pd_header = data['whole_pd_header']
        whole_pd_header2 = data['whole_pd_header2']
        whole_pd_header3 = data['whole_pd_header3']

        self.whole_header = whole_header
        self.whole_header2 = whole_header2
        self.whole_df = whole_df
        self.whole_pd_header = whole_pd_header
        self.whole_pd_header2 = whole_pd_header2
        self.whole_pd_header3 = whole_pd_header3

        self.title_label.setText(title_str)

        self.current_whole_df = self.whole_df.copy()
        self.caculate_and_show_data()
        pass

    def query_slot(self, sym: str, days: int = 365):
        try:
            self.code = sym
            self.title_label.setText(self.code + ' ' + self.name)
            self.current_whole_df = self.getDataFromNet(self.code).copy()
            return self.caculate_and_show_data()
        except Exception:
            print(traceback.print_exc())

    def caculate_and_show_data(self):
        df = self.current_whole_df.reset_index(drop=True)
        tradeDate_list = df['Date'].values.tolist()
        x = range(len(df))
        xTick_show = []
        if len(tradeDate_list) > 100:
            x_dur = math.ceil(len(tradeDate_list) / 20)
        else:
            x_dur = math.ceil(len(tradeDate_list) / 5)
        # print('x_dur:', x_dur)
        # print('Data:\n', df)
        for i in range(0, len(tradeDate_list), x_dur):
            xTick_show.append((i, re.sub('[-]', '', str(tradeDate_list[i]))))
        if len(tradeDate_list) % 20 != 0:
            xTick_show.append((len(tradeDate_list) - 1, re.sub('[-]', '', str(tradeDate_list[-1]))))
        candle_data = []
        segment_data = []
        vol_data = []
        for i, row in df.iterrows():
            candle_data.append((i, row['Open'], row['Close'], row['Low'], row['High']))
            segment_data.append((i, row['MACD']))
            vol_data.append((i, row['Open'], row['Close'], row['Volume']))

        self.current_whole_data = df.loc[:, self.whole_pd_header].values.tolist()
        self.current_whole_data2 = df.loc[:, self.whole_pd_header2].values.tolist()
        # 开始配置显示的内容
        self.pw.clear()
        self.pw2.clear()
        self.pw3.clear()
        self.pw4.clear()
        self.func_item_list.clear()

        xax = self.pw.getAxis('bottom')
        xax.setTicks([xTick_show])
        xax2 = self.pw2.getAxis('bottom')
        xax2.setTicks([xTick_show])
        xax3 = self.pw3.getAxis('bottom')
        xax3.setTicks([xTick_show])
        xax4 = self.pw4.getAxis('bottom')
        xax4.setTicks([xTick_show])

        # 画K线
        candle_fixed_target = CandlestickItem(candle_data)
        self.main_fixed_target_list.append(candle_fixed_target)
        self.pw.addItem(candle_fixed_target)

        self.pw.addLegend(size=(40, 40))

        if stock_index == 1:
            mad_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['md'].values.tolist()),
                                                pen=pg.mkPen({'color': 'blue', 'width': 2}),
                                                connect='finite')
            upper_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['upper'].values.tolist()),
                                                  pen=pg.mkPen({'color': 'red', 'width': 2}),
                                                  connect='finite')
            lower_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['lower'].values.tolist()),
                                                  pen=pg.mkPen({'color': 'green', 'width': 2}),
                                                  connect='finite')
            self.pw.addItem(mad_fixed_target)
            self.pw.addItem(upper_fixed_target)
            self.pw.addItem(lower_fixed_target)

            # self.pw.plot(y=df['md'], pen='blue', name='中轨')
            # self.pw.plot(y=df['upper'], pen='red', name='上轨')
            # self.pw.plot(y=df['lower'], pen='green', name='下轨')
        elif stock_index == 2:
            ma5_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['ma5'].values.tolist()),
                                                pen=pg.mkPen({'color': self.color_ma_5, 'width': 2}),
                                                connect='finite')
            ma10_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['ma10'].values.tolist()),
                                                 pen=pg.mkPen({'color': self.color_ma_10, 'width': 2}),
                                                 connect='finite')
            ma20_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['ma20'].values.tolist()),
                                                 pen=pg.mkPen({'color': self.color_ma_20, 'width': 2}),
                                                 connect='finite')
            ma30_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['ma30'].values.tolist()),
                                                 pen=pg.mkPen({'color': self.color_ma_30, 'width': 2}),
                                                 connect='finite')
            ma60_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['ma60'].values.tolist()),
                                                 pen=pg.mkPen({'color': self.color_ma_60, 'width': 2}),
                                                 connect='finite')
            self.pw.addItem(ma5_fixed_target)
            self.pw.addItem(ma10_fixed_target)
            self.pw.addItem(ma20_fixed_target)
            self.pw.addItem(ma30_fixed_target)
            self.pw.addItem(ma60_fixed_target)
            # self.pw.plot(y=df['ma5'], pen='#fffffb', name='5日均线')
            # self.pw.plot(y=df['ma10'], pen='#ffd400', name='10日均线')
            # self.pw.plot(y=df['ma20'], pen='#ef5b9c', name='20日均线')
            # self.pw.plot(y=df['ma30'], pen='#1d953f', name='30日均线')
            # self.pw.plot(y=df['ma60'], pen='#102b6a', name='60日均线')

        self.vLine = pg.InfiniteLine(angle=90, movable=False)
        self.hLine = pg.InfiniteLine(angle=0, movable=False)
        self.label = pg.TextItem()
        self.pw.addItem(self.vLine, ignoreBounds=True)
        self.pw.addItem(self.hLine, ignoreBounds=True)
        self.pw.addItem(self.label, ignoreBounds=True)

        # 成交量
        vol_fixed_target = VolItem(vol_data)
        self.pw2.addItem(vol_fixed_target)
        self.vLine2 = pg.InfiniteLine(angle=90, movable=False)
        self.hLine2 = pg.InfiniteLine(angle=0, movable=False)
        self.label2 = pg.TextItem()
        self.pw2.addItem(self.vLine2, ignoreBounds=True)
        self.pw2.addItem(self.hLine2, ignoreBounds=True)
        self.pw2.addItem(self.label2, ignoreBounds=True)
        self.pw2.addLegend(size=(40, 40))

        # 指标 MACD
        self.vLine3 = pg.InfiniteLine(angle=90, movable=False)
        self.hLine3 = pg.InfiniteLine(angle=0, movable=False)
        self.label3 = pg.TextItem()
        self.pw3.addItem(self.vLine3, ignoreBounds=True)
        self.pw3.addItem(self.hLine3, ignoreBounds=True)
        self.pw3.addItem(self.label3, ignoreBounds=True)
        self.pw3.addLegend(size=(40, 40))

        # 指标 KDJ
        self.vLine4 = pg.InfiniteLine(angle=90, movable=False)
        self.hLine4 = pg.InfiniteLine(angle=0, movable=False)
        self.label4 = pg.TextItem()
        self.pw4.addItem(self.vLine4, ignoreBounds=True)
        self.pw4.addItem(self.hLine4, ignoreBounds=True)
        self.pw4.addItem(self.label4, ignoreBounds=True)
        self.pw4.addLegend(size=(40, 40))

        # macd
        segment_fixed_target = SegmenttickItem(segment_data)
        diff_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['DIFF'].values.tolist()),
                                             pen=pg.mkPen({'color': self.color_ma_5, 'width': 1}),
                                             connect='finite')
        dea_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['DEA'].values.tolist()),
                                            pen=pg.mkPen({'color': self.color_ma_10, 'width': 1}),
                                            connect='finite')
        self.main_fixed_target_list.append(diff_fixed_target)
        self.main_fixed_target_list.append(dea_fixed_target)
        self.main_fixed_target_list.append(segment_fixed_target)
        self.pw3.addItem(segment_fixed_target)
        self.pw3.addItem(diff_fixed_target)
        self.pw3.addItem(dea_fixed_target)
        self.pw.setXLink(self.pw)
        self.pw2.setXLink(self.pw)
        self.pw3.setXLink(self.pw)

        # 指标
        kdjk_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['kdj_k'].values.tolist()),
                                             pen=pg.mkPen({'color': self.color_ma_10, 'width': 1}),
                                             connect='finite')
        kdjd_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['kdj_d'].values.tolist()),
                                             pen=pg.mkPen({'color': self.color_ma_60, 'width': 1}),
                                             connect='finite')
        kdjj_fixed_target = pg.PlotCurveItem(x=np.array(x), y=np.array(df['kdj_j'].values.tolist()),
                                             pen=pg.mkPen({'color': self.color_ma_20, 'width': 1}),
                                             connect='finite')

        self.main_fixed_target_list.append(kdjk_fixed_target)
        self.main_fixed_target_list.append(kdjd_fixed_target)
        self.main_fixed_target_list.append(kdjj_fixed_target)
        self.pw4.addItem(kdjk_fixed_target)
        self.pw4.addItem(kdjd_fixed_target)
        self.pw4.addItem(kdjj_fixed_target)

        self.pw4.setXLink(self.pw)

        self.vb = self.pw.getViewBox()
        self.proxy = pg.SignalProxy(self.pw.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.proxy2 = pg.SignalProxy(self.pw2.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.proxy3 = pg.SignalProxy(self.pw3.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.proxy3 = pg.SignalProxy(self.pw4.scene().sigMouseMoved, rateLimit=60, slot=self.mouseMoved)
        self.pw.enableAutoRange()
        self.pw2.enableAutoRange()
        self.pw3.enableAutoRange()
        self.pw4.enableAutoRange()
        self.pw2.setYRange(df['Volume'].min(), df['Volume'].max())
        return True

    def mouseMoved(self, evt):
        pos = evt[0]
        if self.pw.sceneBoundingRect().contains(pos):
            mousePoint = self.vb.mapSceneToView(pos)
            index = int(mousePoint.x())
            if 0 <= index < len(self.current_whole_data):
                target_data = self.current_whole_data[index]
                html_str = ''
                for i, item in enumerate(self.whole_header):
                    html_str += f"<br/>{item}:{target_data[i]}"
                self.label.setHtml(html_str)
                self.label.setPos(mousePoint.x(), mousePoint.y())
            self.vLine.setPos(mousePoint.x())
            self.hLine.setPos(mousePoint.y())
            self.vLine2.setPos(mousePoint.x())
            self.hLine2.setPos(mousePoint.y())
            self.vLine3.setPos(mousePoint.x())
            self.hLine3.setPos(mousePoint.y())
            self.vLine4.setPos(mousePoint.x())
            self.hLine4.setPos(mousePoint.y())
        pass

    def add_mark3(self, data_index_list: List[Any], data_str_list: List[str]):
        '''添加标记'''
        for i, i_item in enumerate(data_index_list):
            temp_str = data_str_list[i]
            targetItem = pg.TargetItem(
                pos=(i_item[0], i_item[1]),
                size=20,
                symbol='star',
                movable=False,
                pen='#FF0000'
            )
            targetItem.setLabel(
                temp_str,
                {
                    "anchor": QtCore.QPointF(0.5, 0.5),
                    "offset": QtCore.QPoint(70, 0),
                    "color": "#FF0000"
                }
            )
            self.mark_list.append(targetItem)
            self.pw.addItem(targetItem)
        pass

    def remove_mark3(self):
        '''去除标记'''
        for item in self.mark_list:
            self.pw.removeItem(item)
        pass

    def mouseClicked(self, evt):
        pass

    def updateViews(self):
        pass

    def combox_main_figure_index_currentIndexChanged(self, cur_i: int):
        cur_txt = self.combox_main_figure_index.currentText()
        if cur_txt == self.please_select_str:
            return
        cur_code = self.main_figure_index_map[cur_txt]
        global stock_index
        # 布林线
        if cur_code == 'a':
            stock_index = 1
            self.caculate_and_show_data()
        elif cur_code == 'b':
            stock_index = 2
            self.caculate_and_show_data()

        pass

    # 模式识别
    def pattern_combox_currentIndexChanged(self, cur_i: int):
        cur_txt = self.pattern_combox.currentText()
        if cur_txt == self.please_select_str:
            return
        cur_content = self.k_content[cur_i]

        self.content_tip.setText(cur_txt + ' = ' + cur_content)

        mytalib = talib
        f = getattr(mytalib, self.K_method[cur_i])
        self.current_whole_df['star'] = f(self.current_whole_df['Open'].values, self.current_whole_df['High'].values,
                                          self.current_whole_df['Low'].values, self.current_whole_df['Close'].values)
        self.current_whole_df = self.current_whole_df.reset_index(drop=True)
        # self.caculate_and_show_data()
        print('star:', self.current_whole_df['star'])

    # 选择周期
    def duration_combox_currentIndexChanged(self, cur_i: int):
        cur_txt = self.duration_combox.currentText()
        if cur_txt == self.please_select_str:
            return
        cur_code = self.duration_map[cur_txt]
        right_point = res_date_normal_str()
        # 今年
        if cur_code == 'a':
            self.left_point = res_current_year_first_day()
        # 第一年
        elif cur_code == 'b':
            self.left_point = res_pre_N_year_first_day(1)
        # 第二年
        elif cur_code == 'c':
            self.left_point = res_pre_N_year_first_day(2)
        elif cur_code == 'd':
            self.left_point = res_pre_N_year_first_day(3)
        elif cur_code == 'e':
            self.left_point = res_pre_N_year_first_day(5)
        elif cur_code == 'f':
            self.left_point = res_pre_N_year_first_day(10)
        else:
            return

        df = self.whole_df.copy()
        df['o_date'] = pd.to_datetime(df['Date'])
        self.current_whole_df = df.loc[(df['o_date'] >= self.left_point) & (df['o_date'] <= right_point)].copy()
        self.current_whole_df = self.current_whole_df.reset_index(drop=True)
        self.caculate_and_show_data()
        #        t1 = threading.Thread(target=self.buy_point_on_ma, args=('buy_point_on_ma',))  # 创建线程1
        #        t2 = threading.Thread(target=self.sell_point_on_ma, args=('sell_point_on_ma',))  # 创建线程2
        t3 = threading.Thread(target=self.buy_point_on_boll, args=('buy_point_on_boll',))  # 创建线程3
        t4 = threading.Thread(target=self.sell_point_on_boll, args=('sell_point_on_boll',))  # 创建线程4
        #        t5 = threading.Thread(target=self.look_long_up_shadow, args=('look_long_up_shadow',))  # 创建线程4

        # t1.start()  # 启动线程1
        # t2.start()  # 启动线程2
        t3.start()  # 启动线程3
        t4.start()  # 启动线程4
        #        t5.start()  # 启动线程5

        #        t1.join()  # 等待子线程1执行完毕
        #       t2.join()  # 等待子线程2执行完毕
        t3.join()  # 等待子线程3执行完毕
        t4.join()  # 等待子线程4执行完毕
        #        t5.join()  # 等待子线程5执行完毕
        pass

    def func_combox_currentIndexChanged(self, cur_i: int):
        cur_txt = self.func_combox.currentText()
        if cur_txt == self.please_select_str:
            return
        cur_code = self.func_map[cur_txt]
        df = self.current_whole_df.copy()
        if cur_code == 'a':
            # 多头排列 start
            df['count'] = range(len(df))
            df['duo'] = 0
            df.loc[(df['ma5'] > df['ma10']) & (df['ma10'] > df['ma20']) & (df['ma20'] > df['ma30']) & (
                    df['ma30'] > df['ma60']), 'duo'] = 1

            df['ext_0'] = df['duo'] - df['duo'].shift(1)
            df['ext_1'] = df['duo'] - df['duo'].shift(-1)
            duo_pre_df = df.loc[df['ext_0'] == 1].copy()
            duo_fix_df = df.loc[df['ext_1'] == 1].copy()

            pre_count_list = duo_pre_df['count'].values.tolist()
            pre_date_list = duo_pre_df['Date'].values.tolist()
            fix_count_list = duo_fix_df['count'].values.tolist()
            fix_date_list = duo_fix_df['Date'].values.tolist()
            if fix_count_list[0] < pre_count_list[0]:
                fix_count_list = fix_count_list[1:]
                fix_date_list = fix_date_list[1:]
            if fix_count_list[-1] < pre_count_list[-1]:
                pre_count_list = pre_count_list[0:-1]
                pre_date_list = pre_date_list[0:-1]
            font = QtGui.QFont()
            font.setPixelSize(9)
            for i, item in enumerate(fix_count_list):
                # 排除掉多头排列三日以下的区间
                if item - pre_count_list[i] <= 3:
                    continue
                lr = pg.LinearRegionItem([pre_count_list[i], item], movable=False,
                                         brush=(self.color_up[0], self.color_up[1], self.color_up[2], 50))
                lr.setZValue(-100)
                label_l = pg.InfLineLabel(lr.lines[0], pre_date_list[i], position=0.90, rotateAxis=(1, 0),
                                          anchor=(1, 1), color=self.color_up)
                label_l.setFont(font)
                label_r = pg.InfLineLabel(lr.lines[1], fix_date_list[i], position=0.90, rotateAxis=(1, 0),
                                          anchor=(1, 1), color=self.color_up)
                label_r.setFont(font)
                self.func_item_list.append(lr)
                self.pw.addItem(lr)
            # 多头排列 end
            pass
        elif cur_code == 'b':
            # 空头排列 start
            df['count'] = range(len(df))
            df['duo'] = 0
            df.loc[(df['ma5'] < df['ma10']) & (df['ma10'] < df['ma20']) & (df['ma20'] < df['ma30']) & (
                    df['ma30'] < df['ma60']), 'duo'] = 1

            df['ext_0'] = df['duo'] - df['duo'].shift(1)
            df['ext_1'] = df['duo'] - df['duo'].shift(-1)
            duo_pre_df = df.loc[df['ext_0'] == 1].copy()
            duo_fix_df = df.loc[df['ext_1'] == 1].copy()

            pre_count_list = duo_pre_df['count'].values.tolist()
            pre_date_list = duo_pre_df['Date'].values.tolist()
            fix_count_list = duo_fix_df['count'].values.tolist()
            fix_date_list = duo_fix_df['Date'].values.tolist()
            if fix_count_list[0] < pre_count_list[0]:
                fix_count_list = fix_count_list[1:]
                fix_date_list = fix_date_list[1:]
            if fix_count_list[-1] < pre_count_list[-1]:
                pre_count_list = pre_count_list[0:-1]
                pre_date_list = pre_date_list[0:-1]
            font = QtGui.QFont()
            font.setPixelSize(9)
            for i, item in enumerate(fix_count_list):
                # 排除掉空头排列三日以下的区间
                if item - pre_count_list[i] <= 3:
                    continue
                lr = pg.LinearRegionItem([pre_count_list[i], item], movable=False,
                                         brush=(self.color_down[0], self.color_down[1], self.color_down[2], 50))
                lr.setZValue(-100)
                label_l = pg.InfLineLabel(lr.lines[0], pre_date_list[i], position=0.90, rotateAxis=(1, 0),
                                          anchor=(1, 1), color=self.color_down)
                label_l.setFont(font)
                label_r = pg.InfLineLabel(lr.lines[1], fix_date_list[i], position=0.90, rotateAxis=(1, 0),
                                          anchor=(1, 1), color=self.color_down)
                label_r.setFont(font)
                self.func_item_list.append(lr)
                self.pw.addItem(lr)
            # 空头排列 end
            pass
        elif cur_code == 'c':
            # 20日线斜率为正 start
            df['count'] = range(len(df))
            df['ext_0'] = df['ma20'] - df['ma20'].shift(1)
            df['ext_1'] = 0
            df.loc[df['ext_0'] > 0, 'ext_1'] = 1
            df['ext_2'] = df['ext_1'] - df['ext_1'].shift(1)
            df['ext_3'] = df['ext_1'] - df['ext_1'].shift(-1)
            duo_pre_df = df.loc[df['ext_2'] == 1].copy()
            duo_fix_df = df.loc[df['ext_3'] == 1].copy()

            pre_count_list = duo_pre_df['count'].values.tolist()
            pre_date_list = duo_pre_df['Date'].values.tolist()
            fix_count_list = duo_fix_df['count'].values.tolist()
            fix_date_list = duo_fix_df['Date'].values.tolist()
            if fix_count_list[0] < pre_count_list[0]:
                fix_count_list = fix_count_list[1:]
                fix_date_list = fix_date_list[1:]
            if fix_count_list[-1] < pre_count_list[-1]:
                pre_count_list = pre_count_list[0:-1]
                pre_date_list = pre_date_list[0:-1]
            font = QtGui.QFont()
            font.setPixelSize(9)
            for i, item in enumerate(fix_count_list):
                # if item - pre_count_list[i] <= 3:
                #     continue
                lr = pg.LinearRegionItem([pre_count_list[i], item], movable=False,
                                         brush=(self.color_up[0], self.color_up[1], self.color_up[2], 50))
                lr.setZValue(-100)
                label_l = pg.InfLineLabel(lr.lines[0], pre_date_list[i], position=0.90, rotateAxis=(1, 0),
                                          anchor=(1, 1), color=self.color_up)
                label_l.setFont(font)
                label_r = pg.InfLineLabel(lr.lines[1], fix_date_list[i], position=0.90, rotateAxis=(1, 0),
                                          anchor=(1, 1), color=self.color_up)
                label_r.setFont(font)
                self.func_item_list.append(lr)
                self.pw.addItem(lr)
            # 20日线斜率为正 end
            pass
        elif cur_code == 'd':
            # 阶段最高点最低点 start
            # 最高点
            df['ext_0'] = df['closePrice'].cummax()
            df['ext_1'] = df['ext_0'] - df['ext_0'].shift(1)
            # 最低点
            df['ext_2'] = df['closePrice'].cummin()
            df['ext_3'] = df['ext_2'] - df['ext_2'].shift(1)

            max_point_df = df.loc[df['ext_1'] == 0].copy()
            min_point_df = df.loc[df['ext_3'] == 0].copy()
            # 阶段最高点最低点 end
            pass
        pass

    def getDataFromNet(self, code):
        df = ak.stock_zh_a_hist(symbol=str(code), period="daily", adjust="qfq").dropna()
        # 格式化列名，用于之后的绘制
        df.rename(
            columns={
                '日期': 'Date', '开盘': 'Open',
                '最高': 'High', '最低': 'Low',
                '涨跌幅': 'Increase',
                '收盘': 'Close', '成交量': 'Volume'},
            inplace=True)

        # 计算指标
        close_list = df['Close']
        df['DIFF'], df['DEA'], df['MACD'] = talib.MACD(close_list, fastperiod=12, slowperiod=26, signalperiod=9)
        df["ma5"] = df["Close"].rolling(5).mean()
        df["ma10"] = df["Close"].rolling(10).mean()
        df["ma20"] = df["Close"].rolling(20).mean()
        df["ma30"] = df["Close"].rolling(30).mean()
        df["ma60"] = df["Close"].rolling(60).mean()

        # 计算EMA(12)和EMA(16)
        df['EMA12'] = df['Close'].ewm(alpha=2 / 13, adjust=False).mean()
        df['EMA26'] = df['Close'].ewm(alpha=2 / 27, adjust=False).mean()

        # df['md'] = df['Close'].rolling(26).mean()
        # df['tmp2'] = df['Close'].rolling(20).std()
        # df['upper'] = df['md'] + 2 * df['tmp2']
        # df['lower'] = df['md'] - 2 * df['tmp2']

        df['upper'], df['md'], df['lower'] = talib.BBANDS(df['Close'],
                                                          timeperiod=13, nbdevup=2, nbdevdn=2, matype=0)

        df['kdj_k'], df['kdj_d'] = talib.STOCH(df['High'], df['Low'], df['Close'], fastk_period=9,
                                               slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
        df['kdj_j'] = 3 * df['kdj_k'] - 2 * df['kdj_d']
        if len(df['Date']) > 100:
            df = df.drop(df.head(100).index)
        self.whole_df = df.reset_index(drop=True)
        return df

    def code_combox_currentIndexChanged(self, cur_i: int):
        cur_txt = self.code_combox.currentText()
        print("cur_txt:", cur_txt, " self.please_select_str:", self.please_select_str)
        if cur_txt == self.please_select_str:
            return
        self.title_label.setText(cur_txt)
        self.getDataFromNet(cur_txt)
        self.current_whole_df = self.whole_df.copy()
        self.caculate_and_show_data()
        pass

    def clear_func_btn_clicked(self):
        for item in self.func_item_list:
            self.pw.removeItem(item)
        self.func_item_list.clear()
        pass

    def buy_point_on_ma(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        mark_index_list = []
        mark_str_list = []
        local_df = self.current_whole_df
        while cnt <= len(local_df) - 1:
            try:
                # 规则1，收盘价连续三天上扬
                if local_df.iloc[cnt]['Close'] < local_df.iloc[cnt + 1]['Close'] < local_df.iloc[cnt + 2]['Close']:
                    # 规则2,5日均线连续三天上扬
                    if local_df.iloc[cnt]['ma5'] < local_df.iloc[cnt + 1]['ma5'] < local_df.iloc[cnt + 2]['ma5']:
                        # 规则3，第3天，收盘价上穿5日均线
                        if local_df.iloc[cnt + 1]['ma5'] > local_df.iloc[cnt]['Close'] and local_df.iloc[cnt + 2]['ma5'] \
                                < local_df.iloc[cnt + 1]['Close']:
                            # print("Buy Point by MA on:" + local_df.iloc[cnt]['Date'])
                            mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                            temp_str = f"{cnt} {local_df.iloc[cnt]['Close']}"
                            mark_str_list.append(temp_str)
            except:  # 有几天是没5日均线的，所以用except处理异常
                pass
            cnt = cnt + 1
        self.add_mark(mark_index_list, mark_str_list, "#A2007C", -50, 30, 'star')
        pass

    def sell_point_on_ma(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        local_df = self.current_whole_df
        cnt = 0
        mark_index_list = []
        mark_str_list = []
        while cnt <= len(local_df) - 1:
            try:
                # 规则1，收盘价连续三天下跌
                if local_df.iloc[cnt]['Close'] > local_df.iloc[cnt + 1]['Close'] > local_df.iloc[cnt + 2]['Close']:
                    # 规则2,5日均线连续三天下跌
                    if local_df.iloc[cnt]['ma5'] > local_df.iloc[cnt + 1]['ma5'] > local_df.iloc[cnt + 2]['ma5']:
                        # 规则3，第3天，收盘价下穿5日均线
                        if local_df.iloc[cnt + 1]['ma5'] < local_df.iloc[cnt]['Close'] and local_df.iloc[cnt + 2][
                            'ma5'] > \
                                local_df.iloc[cnt + 1]['Close']:
                            # print("Sell Point by MA on:" + local_df.iloc[cnt]['Date'])
                            mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                            temp_str = f"{cnt} {local_df.iloc[cnt]['Close']}"
                            mark_str_list.append(temp_str)
            except:  # 有几天是没5日均线的，所以用except处理异常
                pass
            cnt = cnt + 1
            # 添加标记
        self.add_mark(mark_index_list, mark_str_list, "#009ad6", 30, 30, 'star')
        pass

    def sell_point_on_macd(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        local_df = self.current_whole_df
        mark_index_list = []
        mark_str_list = []

        while cnt <= len(local_df) - 1:
            try:
                # 规则1：这天DIF值下穿DEA
                if local_df.iloc[cnt]['DIFF'] < local_df.iloc[cnt]['DEA'] and local_df.iloc[cnt - 3]['DIFF'] > \
                        local_df.iloc[cnt - 3]['DEA']:
                    # 规则2：Bar柱是否向下运动
                    if local_df.iloc[cnt]['MACD'] < local_df.iloc[cnt - 3]['MACD']:
                        print("Sell Point by MACD on:" + local_df.iloc[cnt]['Date'])
                        mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                        temp_str = f"{local_df.iloc[cnt]['Date']} {local_df.iloc[cnt]['Close']}"
                        mark_str_list.append(temp_str)

            except:
                pass
            cnt = cnt + 1
        # self.add_mark(mark_index_list, mark_str_list, "#009ad6", 30, 30, 'star')
        self.add_mark(mark_index_list, mark_str_list, "green", 0, 30, 'd')
        pass

    def buy_point_on_macd(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        local_df = self.current_whole_df

        mark_index_list = []
        mark_str_list = []

        while cnt <= len(local_df) - 1:
            try:
                # 规则1：这天DIF值上穿DEA
                # print(name,'1',local_df.iloc[cnt]['DIFF'],',',local_df.iloc[cnt]['DEA'],',',local_df.iloc[cnt-1]['DIFF'],',',local_df.iloc[cnt-1]['DEA'])
                if local_df.iloc[cnt]['DIFF'] > local_df.iloc[cnt]['DEA'] and local_df.iloc[cnt - 3]['DIFF'] < \
                        local_df.iloc[cnt - 3]['DEA']:
                    # 规则2：出现红柱，即MACD值大于0
                    if round(float(local_df.iloc[cnt]['MACD']), 4) > 0:
                        print("Buy Point by MACD on:" + local_df.iloc[cnt]['Date'])
                        mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                        temp_str = f"{local_df.iloc[cnt]['Date']} {local_df.iloc[cnt]['Close']}"
                        mark_str_list.append(temp_str)
            except:
                pass
            cnt = cnt + 1
        self.add_mark(mark_index_list, mark_str_list, "red", 0, 30, 'd')
        pass


    def buy_point_on_boll(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        local_df = self.current_whole_df
        mark_index_list = []
        mark_str_list = []

        while cnt <= len(local_df) - 1:
            try:
                # 当收盘价从下轨线(low_bb)突破时（前一天收盘价应当位于low_bb下方），买入股票
                if local_df.iloc[cnt]['Close'] > local_df.iloc[cnt]['md'] and local_df.iloc[cnt - 1]['Close'] < local_df.iloc[cnt + 1]['md']:
                    # 放量突破中轨
                    if local_df.iloc[cnt]['Volume'] > local_df.iloc[cnt-1]['Volume']*1.5:
                        print("buy Point by boll on:" + local_df.iloc[cnt]['Date'])
                        mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                        temp_str = f"{local_df.iloc[cnt]['Date']} {local_df.iloc[cnt]['Close']}"
                        mark_str_list.append(temp_str)
            except:
                pass
            cnt = cnt + 1
        self.add_mark(mark_index_list, mark_str_list, "red", 0, 30, 'arrow_up')
        pass
    def sell_point_on_boll(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        local_df = self.current_whole_df
        mark_index_list = []
        mark_str_list = []

        while cnt <= len(local_df) - 1:
            try:
                # 当收盘价从上轨线（up_bb)跌破时（前一天收盘价应当位于up_bb上方），卖出股票
                if local_df.iloc[cnt]['Close'] > local_df.iloc[cnt]['upper'] and local_df.iloc[cnt + 1]['Close'] < local_df.iloc[cnt + 1]['upper']:
                    if local_df.iloc[cnt+3]['Increase'] < 3.0 and local_df.iloc[cnt+2]['Increase'] and local_df.iloc[cnt+1]['Increase']:
                        print("Sell Point by boll on:" + local_df.iloc[cnt]['Date'])
                        mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                        temp_str = f"{local_df.iloc[cnt]['Date']} {local_df.iloc[cnt]['Close']}"
                        mark_str_list.append(temp_str)
            except:
                pass
            cnt = cnt + 1
        self.add_mark(mark_index_list, mark_str_list, "green", 0, 30, 'arrow_down')
        pass
    def add_mark(self, data_index_list: List[Any], data_str_list: List[str], col, off, size, symbol_type):
        '''添加标记'''
        for i, i_item in enumerate(data_index_list):
            temp_str = data_str_list[i]
            targetItem = pg.TargetItem(
                pos=(i_item[0], i_item[1]),
                size=size,
                symbol=symbol_type,
                movable=False,
                pen=col,
                labelOpts={'color': col}
            )
            if 0:
                targetItem.setLabel(
                    temp_str,
                    {
                        "anchor": QtCore.QPointF(1.5, 1.5),
                        "offset": QtCore.QPoint(70, off),
                        "color": col
                    }
                )
            self.mark_list.append(targetItem)
            self.pw.addItem(targetItem)
        pass

    def remove_mark(self):
        '''去除标记'''
        for item in self.mark_list:
            self.pw.removeItem(item)
        pass

    def long_up_shadow(self, o, c, h):
        return True if (h - c) / c >= 0.07 and (h - o) / o >= 0.07 else False

    # 查找上影线
    def look_long_up_shadow(self, name):
        cnt = 0
        print(f'{name} 线程开始执行')
        local_df = self.current_whole_df
        mark_index_list = []
        mark_str_list = []
        while cnt <= len(local_df) - 1:
            try:
                if self.long_up_shadow(local_df.iloc[cnt]['Open'], local_df.iloc[cnt]['Close'],
                                       local_df.iloc[cnt]['High']):
                    mark_index_list.append([cnt, local_df.iloc[cnt]['Close']])
                    temp_str = f"{cnt} {local_df.iloc[cnt]['Close']}"
                    mark_str_list.append(temp_str)
            except:  # 有几天是没5日均线的，所以用except处理异常
                pass
            cnt = cnt + 1
            # 添加标记
            if len(mark_str_list):
                self.add_mark(mark_index_list, mark_str_list, "green", 30, 20, 'p')

    pass


def drawKLine():
    # df = pd.read_csv('6005192.csv', encoding='utf-8')
    # 002865 钧达股份
    # df = ak.stock_zh_a_hist(symbol='002865', period="daily", start_date="20200820", end_date="20221114",
    #                        adjust="qfq").dropna()
    df = ak.stock_zh_a_hist(symbol='002865', period="daily", adjust="qfq").dropna()
    # df.index = pd.to_datetime(df.index)
    # 格式化列名，用于之后的绘制
    df.rename(
        columns={
            '日期': 'Date', '开盘': 'Open',
            '最高': 'High', '最低': 'Low',
            '涨跌幅': 'Increase',
            '收盘': 'Close', '成交量': 'Volume'},
        inplace=True)

    # 计算指标
    close_list = df['Close']
    df['DIFF'], df['DEA'], df['MACD'] = talib.MACD(close_list, fastperiod=12, slowperiod=26, signalperiod=9)
    df["ma5"] = df["Close"].rolling(5).mean()
    df["ma10"] = df["Close"].rolling(10).mean()
    df["ma20"] = df["Close"].rolling(20).mean()
    df["ma30"] = df["Close"].rolling(30).mean()
    df["ma60"] = df["Close"].rolling(60).mean()

    # 计算EMA(12)和EMA(16)
    df['EMA12'] = df['Close'].ewm(alpha=2 / 13, adjust=False).mean()
    df['EMA26'] = df['Close'].ewm(alpha=2 / 27, adjust=False).mean()

    df['md'] = df['Close'].rolling(26).mean()
    df['tmp2'] = df['Close'].rolling(20).std()
    df['upper'] = df['md'] + 2 * df['tmp2']
    df['lower'] = df['md'] - 2 * df['tmp2']

    df = df.drop(df.head(100).index)

    whole_pd_header = ['Date', 'Close', 'Open', 'High', 'Low', 'Increase']
    whole_pd_header2 = ['Date', 'DIFF', 'DEA', 'MACD']
    whole_pd_header3 = ['Date', 'kdj_k', 'kdj_d', 'kdj_j']

    line_data = {
        'title_str': '贵州茅台',
        'whole_header': ['日期', '收盘价', '开盘价', '最高价', '最低价', '涨跌幅'],
        'whole_header2': ['日期', 'DIFF', 'DEA', 'MACD'],
        'whole_pd_header': whole_pd_header,
        'whole_pd_header2': whole_pd_header2,
        'whole_pd_header3': whole_pd_header3,
        'whole_df': df
    }

    app = QtWidgets.QApplication(sys.argv)
    t_win = PyQtGraphLineWidget(df)
    t_win.showMaximized()  # 最大化显示
    t_win.show()
    t_win.set_data(line_data)
    sys.exit(app.exec_())
